#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ast
import json
import time
from io import BytesIO
from random import random

import requests
from PIL import Image, ImageDraw

headers = {
    'Connection': "keep-alive" ,
    'sec-ch-ua':'"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"' ,
    'Accept' :'application/json, text/plain, */*' ,
    'X-Client-Type':"pc" ,
    'sec-ch-ua-mobile': "?0" ,
    'User-Agent':"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36" ,
    'Content-Type':'application/json' ,
    'Origin':'https://www.bjjnts.cn' ,
    'Sec-Fetch-Site':'same-site' ,
    'Sec-Fetch-Mode':'cors' ,
    'Sec-Fetch-Dest':'empty' ,
    'Referer':'https://www.bjjnts.cn/user/login',
    'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8'
}

def create_req(method="POST",headers=headers, others=None, url=None):
    session = requests.session()
    if method == "POST":
        resp = session.post(url= url, data=json.dumps(others), headers=headers)
        if resp.status_code == 200:
            req = resp.text.replace("null", "None")
        elif resp.status_code == 201:
            req = resp.text.replace("null", "None")
        else:
            return resp.text
    if method == "GET":

        resp = session.get(url=url, headers=headers)
        if resp.status_code == 200:
            req = resp.text.replace("null", "None")
        else:
            return resp.text
    time.sleep(1)
    return ast.literal_eval(req)


def getUserClass(accessToken:str):
    url = 'https://apif.bjjnts.cn/student-center/study'
    other_header = {
        "Authorization": "Bearer "+ accessToken,
        "Refer":"https://www.bjjnts.cn/mine/student/study"
    }
    headers.update(other_header)
    resp = create_req(method="GET", headers=headers, url=url)

    if resp[0]["progress"] > 0.9999:
        return []
    return resp[0]["courseMap"]


def getUserInfo(user:dict):
    url = "https://apif.bjjnts.cn/account/login"
    data = {
        "username": user["username"],
        "password": user["password"],
        "type": 1
    }
    headers.update({"Referer": "https://www.bjjnts.cn/user/login"})

    userinfo = create_req("POST", headers, data, url)

    return userinfo


def getUserTopic(accessToken:str, courseID:str, classID:str):
    url = "https://apif.bjjnts.cn/courses/test-preview?course_id={}&class_id={}".format(courseID, classID)

    other_header = {
        "Authorization": "Bearer " + accessToken,
        "Refer": "https://www.bjjnts.cn/study?course_id={}&class_id={}".format(courseID, classID)
    }

    headers.update(other_header)
    resp = create_req(method="GET", headers=headers, url=url)

    return resp


def getMovieInfo(accessToken:str, classID:str, unitID:str, courseID:str):
    url = "https://apif.bjjnts.cn/course-units/{}?class_id={}".format(unitID, classID)
    other_header = {
        "Authorization": "Bearer " + accessToken,
        "Refer": "https://www.bjjnts.cn/study/video?class_id={}&course_id={}&unit_id={}".format( classID, courseID, unitID)
    }

    headers.update(other_header)

    resp = create_req(method="GET", headers=headers, url=url)

    movieinfo = {
        "class_id": classID,
        "course_id": resp["video"]["course_id"],
        "unit_id": resp["video"]["unit_id"],
        "video_id": resp["video"]["id"],
        "time": resp["video"]["time"],
        "progress_time": resp["progress_time"],
        'chapter': resp['chapter']["title"]
    }

    return movieinfo


def run_study(studyInfo:dict, accessToken:str, isEnd= False):
    study_info = studyInfo
    url = "https://apif.bjjnts.cn/studies?video_id={}&u={}&time={}&unit_id={}&class_id={}".format(
        study_info["video_id"],
        study_info["user_id"],
        study_info["time"],
        study_info["unit_id"],
        study_info["class_id"]
    )
    if studyInfo["time"] == 0:
        url += "&start=1"

    if isEnd :
        url += "&end=1"

    other_header = {
        "Authorization": "Bearer " + accessToken,
        "Refer": "https://www.bjjnts.cn/study/video?class_id={}&course_id={}&unit_id={}".format(studyInfo["class_id"],
                                                                                                studyInfo["course_id"],
                                                                                                studyInfo["unit_id"])
    }
    headers.update(other_header)

    resp_s = create_req(method="POST", headers=headers, url=url)
    print(resp_s, end="")
    resp = ast.literal_eval(str(resp_s))

    # resp = '{"name": "Forbidden", "message": "请人机验证", "code": 2002, "status": 403}'
    # 注意这里要出现人机验证了
    if resp.get("code", 0) == 2002:
        print("2002 人机验证")
        print(smart(accessToken, studyInfo))
    elif resp.get("code", 0) == 2003:
        print("2003 人脸识别")
        print(face(accessToken, studyInfo))

    if resp.get("video_time") != int(resp.get("count_time")):
        print("完成一轮，等待60秒")
        time.sleep(60)
        return run_study(study_info, accessToken)
    return resp


def smart(accessToken, studyInfo):
    "人机验证"
    url = "https://apif.bjjnts.cn/supervises/smart"

    data = {
        "course_id": studyInfo["course_id"],
        "unit_id": studyInfo["unit_id"],
        "class_id": studyInfo["class_id"]
    }
    other_header = {
        "Authorization": "Bearer " + accessToken,
        "Refer": "https://www.bjjnts.cn/study/video?class_id={}&course_id={}&unit_id={}".format(studyInfo["class_id"],
                                                                                                studyInfo["course_id"],
                                                                                                studyInfo["unit_id"])
    }
    headers.update(other_header)

    resp = create_req(method="POST", headers=headers, others=data, url=url)
    return resp


def face(accessToken, studyInfo):
    url = "https://apif.bjjnts.cn/supervises/smart"
    data = {
        "baseImage": str(faceImage()),
        "course_id": studyInfo["course_id"],
        "unit_id": studyInfo["unit_id"],
        "class_id": studyInfo["class_id"]
    }
    other_header = {
        "Authorization": "Bearer " + accessToken,
        "Refer": "https://www.bjjnts.cn/study/video?class_id={}&course_id={}&unit_id={}".format(studyInfo["class_id"],
                                                                                                studyInfo["course_id"],
                                                                                                studyInfo["unit_id"])
    }
    headers.update(other_header)
    resp = create_req(method="POST", headers=headers, others=data, url=url)
    return resp

# 注意这里的userID 要输入你的人脸识别的人脸照片的文件名，不带后缀的
def faceImage(userID=None):
    img_path = './{}.jpg'.format(userID)
    # 从内存中读图片
    content = open(img_path, 'rb').read()
    img = Image.open(BytesIO(content))
    draw = ImageDraw.Draw(img)
    draw.text((int(random()*287), int(random()*287)), str(int(random()*100)), fill=(0, 0, 0))
    return img

    # 往内存中写图片
    img = Image.open(img_path)
    with BytesIO() as out:
        img.save(out, format='JPEG')
        with open('out_stream.jpg', 'wb') as fo:
            fo.write(out.getvalue())


def execTask(needData:dict):
    movieInfo = getMovieInfo(
        accessToken=needData["access_token"],
        classID=needData["classID"],
        unitID=needData["unitID"],
        courseID=needData["courseID"]
    )
    movieInfo.update({"user_id": needData["user_id"], })

    print("-" * 10)
    time.sleep(50)
    print("userUnits {}/{}".format(index, len(userUnits)))
    print("{}共计{}已经完成{}".format(movieInfo["chapter"],movieInfo["time"],movieInfo["progress_time"]))
    print("-" * 10)

    # 开始学习

    study_stat = run_study(studyInfo=movieInfo, accessToken=userinfo["access_token"])






if __name__ == '__main__':

    user = {
        "username": "xxxxxx", # 这里输入账号
        "password": "xxxxxx" # 这里填入密码
    }
    userinfo = getUserInfo(user)
    print(userinfo)

    userCourseMap = getUserClass(accessToken=userinfo["access_token"])
    print("#"*30)

    # 获取章节units,只要course.units的数据
    for index, item in enumerate(userCourseMap):
        userUnits = getUserTopic(accessToken=userinfo["access_token"],
                                 courseID=item["course_id"],
                                 classID=item["class_id"])["course"]

        print("-" * 10)
        print("userCourseMap {}/{}".format(index, len(userCourseMap)), end="")
        print("{}完成进度{}".format(item["course"]["title"],item["progress"]))

        print("-" * 10)

        for index, unit in enumerate(userUnits):

            if unit["units"][0]["progress"] > 0.9999:
                continue
            knowinfo = [
                unit["units"][0]["title"],
                unit["units"][0]["progress"],
            ]
            needData = {
                "access_token":userinfo["access_token"],
                "classID": item["class_id"],
                "unitID":unit["units"][0]["id"],
                "courseID":item["course_id"],
                "user_id": userinfo["id"]
            }

            study_stat = execTask(needData)

        print("#"*20)
    print("#"*20)



